package com.leyou.task.schedule;

import com.leyou.common.constants.RocketMQConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.joda.time.DateTime;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

import static com.leyou.common.constants.RocketMQConstants.TAGS.ORDER_OVERTIME_TAGS;
import static com.leyou.common.constants.RocketMQConstants.TOPIC.ORDER_TOPIC_NAME;

/**
 * 关闭超时订单的任务
 */
@Slf4j
@Component
@SuppressWarnings("{all}")
public class CloseOverTimeOrder {

    int num = 0;
    /**
     * 测试定时任务
     * fixedRate 固定频率执行
     * fixedDelay 固定延迟
     * fixedRate 如果任务时间大于频率,就会有补偿,计算时间,
     */
    @Scheduled(fixedRate = 2000)
    public void test123(){
        log.info("#####num={}",num);
        try {
            if(num ==3){
                Thread.sleep(5000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("#####执行定时任务");
        num += 1;
    }

    @Autowired
    private RedissonClient client;

//    定义分布式锁的名字
    private String lockName = "ly:order:close:task:lock";

    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    /**
     * 每隔1分钟执行一次，计算出需要关闭订单的创建时间
     * 需要使用分布式锁，确保每次只有一个实例的定时任务执行
     * 保存当前方法执行花费时间不要太长
     * 发送RocketMQ的消息，由order服务消费
     */
    @Scheduled(fixedDelay = 60000)
    public void closeOverTimeOrder(){

        //查询未支付,超时时间大于当前时间,
        //select * from tb_order where status=1 and create_time <=over_time

        /*
        * 为什么使用分布式锁? 这个服务可能部署多个实例,部署集群,但是只能有一个执行成功,
        * 只要有一个实例执行成功了,别的实例就不会再执行了
        *
        * */


        //根据分布锁的名字，生成锁对象，当前并没有访问redis
        RLock lock = client.getLock(lockName);
//        到redis获取分布式锁
        boolean b = false;
        try {
            //
            /**
             * 参数1=等待时间
             *      如果获取锁失败,等待多久再次去获取锁
             * 参数2=锁的有效期,
             *      不能大于定时任务的执行间隔,假如间隔是70s,下一次执行的时候就无法获取锁,
             * 参数3=锁的时间单位
             *
            * */
            b = lock.tryLock(0, 40, TimeUnit.SECONDS);
            if(!b){
//                如果返回false，说明没有获取到锁
                return ;
            }
            log.info("##定时清理订单任务开始");
//            如果得到了锁，执行业务,计算查询订单的时间
            String overTime = DateTime.now().minusMinutes(15).toString("yyyy-MM-dd HH:mm:ss");
//            String overTime = DateTime.now().minusDays(15).toString("yyyy-MM-dd HH:mm:ss");
//            发送rocketmq消息
            String dest = ORDER_TOPIC_NAME + ":" + ORDER_OVERTIME_TAGS;
            rocketMQTemplate.convertAndSend(dest,overTime);
            log.info("##定时清理订单任务结束，overTime：{}",overTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            if(b){
                //            释放锁
                lock.unlock();
            }
        }
    }

    private void clear(){
        //查询未支付,超时时间大于当前时间,
        //select * from tb_order where status=1 and create_time <=over_time
    }
}
